#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <netdb.h>
#include <iostream>
#include <udt.h>

#include "cc.h"
#include "test_util.h"

using namespace std;

void* monitor(void*);

int main(int argc, char* argv[])
{
   if ((3 != argc) || (0 == atoi(argv[2]))) {
      printf("usage: appclient server_ip server_port\n");
      return 0;
   }

   UDTUpDown _udt_;

   struct addrinfo hints, *local, *peer;

   memset(&hints, 0, sizeof(struct addrinfo));

   hints.ai_flags = AI_PASSIVE;
   hints.ai_family = AF_INET;
   hints.ai_socktype = SOCK_STREAM;

   if (0 != getaddrinfo(NULL, "9000", &hints, &local)) {
      printf("incorrect network address.\n");
      return 0;
   }

   UDTSOCKET client = UDT::socket(local->ai_family, local->ai_socktype, local->ai_protocol);

   freeaddrinfo(local);

   if (0 != getaddrinfo(argv[1], argv[2], &hints, &peer))   {
      printf("incorrect server/peer address. %d : %d\n", argv[1], argv[2]);
      return 0;
   }

   // connect to the server, implict bind
   if (UDT::ERROR == UDT::connect(client, peer->ai_addr, peer->ai_addrlen)) {
     // cout << "connect: " << UDT::getlasterror().getErrorMessage() << endl;
      return 0;
   }

   freeaddrinfo(peer);

   int datalen = 100000;
   char* data = new char[datalen];

   pthread_create(new pthread_t, NULL, monitor, &client);

   for (int i = 0; i < 1000000; i ++) {
      int len, offset = 0;

      while (offset < datalen) {
         if (UDT::ERROR == (len = UDT::send(client, data + offset, datalen - offset, 0))) {
//            cout << "send:" << UDT::getlasterror().getErrorMessage() << endl;
            break;
         }

         offset += len;
      }

      if (offset < datalen)
         break;
   }

   UDT::close(client);
   delete [] data;
   return 0;
}


void* monitor(void* s)
{
   UDTSOCKET u = *(UDTSOCKET*)s;

   UDT::TRACEINFO perf;

//   cout << "SendRate(Mb/s)\tRTT(us)\tCWnd\tPktSndPeriod(us)\tRecvACK\tRecvNAK" << endl;

   while (true) {
      sleep(1);

      if (UDT::ERROR == UDT::perfmon(u, &perf)) {
//         cout << "perfmon: " << UDT::getlasterror().getErrorMessage() << endl;
         break;
      }
/*
      cout << perf.mbpsSendRate << "\t\t" 
           << perf.msRTT*1000 << "\t" 
           << perf.pktCongestionWindow << "\t" 
           << perf.usPktSndPeriod << "\t\t\t" 
           << perf.pktRecvACK << "\t" 
           << perf.pktRecvNAK << endl;*/
   }

   return NULL;
}
